package com.onpositive.notes.services;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import com.onpositive.notes.model.ITemplate;
import com.onpositive.notes.model.ITemplateModel;

public class TemplateModelRegistry implements ITemplateModelRegistry {

	private static final long serialVersionUID = -8254337945864771595L;

	private static TemplateModelRegistry instance = null ;
	
	protected TemplateModelRegistry(){}
	
	public static TemplateModelRegistry getInstance() {
		if( instance == null ){
			instance = new TemplateModelRegistry() ;
			instance.init() ;
		}
		
		return instance;
	}
	
	private ArrayList<ITemplateModel<?>> modelsList ;
	
	private HashMap<Locale,ArrayList<ITemplateModel<?>>> localeMap = new HashMap<Locale,ArrayList<ITemplateModel<?>>>() ;
	
	private HashMap<String, ITemplateModel<?>> modelsMap = new HashMap<String, ITemplateModel<?>>();
	
	private HashMap<String,LinkedHashSet<ITemplate>> templateIndex = new HashMap<String,LinkedHashSet<ITemplate>>() ;
	
	private HashMap<String,ArrayList<String>> wordMap = new HashMap<String, ArrayList<String>>() ;
	
	@Override
	public Set<String> getAllTemplateKeys() {
		HashSet<String> result = new HashSet<String>() ;
		
		for( ITemplateModel<?> model : modelsList ){
			List<String> allKeys = model.getAllKeys();
			if(allKeys != null)
				result.addAll(allKeys) ;
		}		
		return result;
	}
	
	@Override
	public Set<String> getAllTemplateKeys(Locale locale) {
		
		HashSet<String> result = new HashSet<String>() ;
		ArrayList<ITemplateModel<?>> models = localeMap.get(locale);
		if( models == null )
			return result ;
		
		for( ITemplateModel<?> model : models ){
			String key = model.getKey(locale) ;
			result.add(key) ;
		}		
		return result;
	}

	@Override
	public List<ITemplateModel<?>> getAllModels() {
		return getAllModels( Locale.getDefault() ) ;
	}
	
	protected void init() {
		
		modelsList = TemplateModelsList.getModelsList() ;
		
		for( ITemplateModel<?> model : modelsList ){
			
			String idLC = model.getId().toLowerCase();
			modelsMap.put( idLC, model) ;	
			
			for( String s : model.getAllKeys() ){
				int ind = s.indexOf(' ') ;
				if(ind < 0 )
					ind = s.length() ;
				
				String s_ = s.substring(0, ind).trim().toLowerCase() ;
				
				ArrayList<String> lst = wordMap.get(s_) ;
				if( lst == null ){
					lst = new ArrayList<String>() ;
					wordMap.put(s_, lst) ;
				}
				lst.add(s.toLowerCase()) ;
				
				if(lst.contains(idLC))
					lst.add(idLC) ;
			}
			
			for( Locale locale : model.getAvailableLocales() ){
				
				ArrayList<ITemplateModel<?>> lst = localeMap.get(locale) ;
				if( lst == null ){
					lst = new ArrayList<ITemplateModel<?>>() ;
					localeMap.put(locale, lst) ;
				}
				lst.add(model) ;				
			}			
		}		
	}


	@Override
	public ITemplateModel<?> getModelById(String id) {
		return modelsMap.get(id) ;
	}

	@Override
	public List<ITemplateModel<?>> getModelsByKey(String key) {
		
		ArrayList<ITemplateModel<?>> result = new ArrayList<ITemplateModel<?>>() ;
		
		for( ITemplateModel<?> model : modelsList ){
			if( model.getAllKeys().contains(key) )
				result.add(model) ;
		}
		return result ;
	}



	@Override
	public List<ITemplateModel<?>> getModelsByKey(String key, Locale locale) {
		
		key = key.toLowerCase() ;
		ArrayList<ITemplateModel<?>> result = new ArrayList<ITemplateModel<?>>() ;
		if(key == null)
			return result ;
		
		ArrayList<ITemplateModel<?>> models = localeMap.get(locale);
		if( models != null ){
			for( ITemplateModel<?> model : models ){
				if( key.equals(model.getKey(locale).toLowerCase() ) )
					result.add(model) ;
			}
		}
		return result ;
	}
	

	@Override
	public Set<ITemplate> getTemplates(ITemplateModel<?> model) {		
		return getTemplates( model.getId() );
	}


	@Override
	public Set<ITemplate> getTemplates(String id) {		
		LinkedHashSet<ITemplate> set = templateIndex.get(id);
		if(set == null){
			set = new LinkedHashSet<ITemplate>() ;
			templateIndex.put(id, set) ;
		}
		return set ;
	}

	@Override
	public List<ITemplateModel<?>> getAllModels(Locale locale) {
		return localeMap.get(locale);
	}

	@Override
	public List<String> getModelsByFirstWord( String key ) {
		return wordMap.get(key) ;
	}

	@Override
	public Set<String> getStartingWords() {
		return new HashSet<String>( wordMap.keySet() );
	}

}
